﻿#ifndef _CELLCLIENT_H_
#define _CELLCLIENT_H_

#include "CELL.h"
#include "CELLObjectPool.hpp"
#include <vector>
#include "CELLBuffer.h"

// 每个客户端的缓冲区控制根据业务需求的差异而调整

// 每次加入一个客户端都会创建一个CELLClient对象，这个对象池归对象池管理
class CELLClient : public ObjectPoolBase<CELLClient, 1024>
{
public:
	CELLClient(SOCKET sock = INVALID_SOCKET, int sendSize = SEND_BUF_SIZE, int recvSize = RECV_BUF_SIZE);

	~CELLClient();

	void destory();

	// 获得本客户端套接字
	SOCKET sockfd();

	// 发回数据
	int SendData(DataHeader* header);

	int SendData(const char* pData, int len);

	// 立即发送发送缓冲区的数据
	int SendDataReal();

	// 接收数据
	int RecvData();

	// 接收有无消息
	bool hasMsg();

	// 发送缓冲区是否有数据需要发送
	bool needWrite();

	// 得到第一条消息
	DataHeader* front_msg();

	// 删除最前面一条消息
	void pop_front_msg();

	// 把心跳计时置0
	void resetDtHeart();

	// 重置上次发送时间_dtSend
	void resetDtSend();

	// 心跳检测
	bool checkHeart(time_t dt);

	// 定时发送消息检测
	bool checkSend(time_t dt);

	// 以下几个为用于调试的成员变量
	// 测试所用id
	int id;
	// 累计发送消息
	int _nSendMsgCount = 1;
	// 累计接收消息
	int _nRecvMsgCount = 1;
#ifdef CELL_USE_IOCP // 如果使用了IOCP模式
	IO_DATA_BASE* makeRecvIOData()
	{
		if (_isPostRecv)
			return nullptr;
		_isPostRecv = true;
		return _recvBuff.makeRecvIOData(_sockfd);
	}

	// 告知缓冲区本次接收到数据的长度
	void recv4Iocp(int nRecv)
	{
		if (!_isPostRecv)
			CELLLog_Error("CELLClient recv4Iocp, _isPostRecv=false");
		_isPostRecv = false;
		_recvBuff.read4iocp(nRecv);
	}

	IO_DATA_BASE* makeSendIOData()
	{
		if (_isPostSend)
			return nullptr;
		_isPostSend = true;
		return _sendBuff.makeSendIOData(_sockfd);
	}

	void send2Iocp(int nSend)
	{
		if (!_isPostSend)
			CELLLog_Error("CELLClient send2Iocp, _isPostSend=false");
		_isPostSend = false;
		_sendBuff.write2iocp(nSend);
	}

	bool isPostIoAction()
	{
		return _isPostRecv || _isPostSend;
	}
#endif // #ifdef CELL_USE_IOCP

private:
	// 上次发送消息数据的时间
	time_t _dtSend;
	// 当前客户端套接字
	SOCKET _sockfd;
	// 接收消息缓冲区
	CELLBuffer _recvBuff;
	// 发送缓冲区
	CELLBuffer _sendBuff;
	// 心跳死亡计时
	time_t _dtHeart;
#ifdef CELL_USE_IOCP // 如果使用了IOCP模式
	bool _isPostRecv = false;
	bool _isPostSend = false;
#endif
};

#endif // #ifndef _CELLCLIENT_H_
